package com.example.musicplayer.windowTools;

import android.app.Activity;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Scroller;

import com.example.musicplayer.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 处理滑动退出activity的类
 */
public class SlideLayout extends FrameLayout {
    private Activity mActivity;
    private Scroller mScroller;
    //上一次滑动的x的值
    private int mLastX;
    //上一次滑动的y的值
    private int mLastY;
    //记录屏幕宽
    private int mScreenWidth;
    //记录屏幕高
    private int mScreenHeight;
    //设定最小x的值，小于这个值时不处理滑动
    private int mMinX;
    //设定最小y的值，小于这个值时不处理滑动
    private int mMinY;
    //是否左右滑动退出，false表示向下滑动退出
    private boolean mHorizontalSlide;
    private boolean mEnable;
    //滑动速度限制，超过这个值立即结束当前activity
    private static final float LIMIT = 3.0f;
    //历史数据记录的最大数量
    private static final int DATA_SIZE = 20;
    //至少需要的历史数据数，少于这个数时不进行退出判断
    private static final int MIN_DATA_SIZE = 5;
    //记录滑动的历史数据
    private List<SlideData> mData = new ArrayList<SlideData>();

    public SlideLayout(Activity activity) {
        this(activity, null, 0, true);
    }

    public SlideLayout(Activity activity, boolean horizontalSlide) {
        this(activity, null, 0, horizontalSlide);
    }

    public SlideLayout(Activity activity, AttributeSet attrs, boolean horizontalSlide) {
        this(activity, attrs, 0, horizontalSlide);
    }

    public SlideLayout(Activity activity, AttributeSet attrs, int defStyleAttr, boolean horizontalSlide) {
        super(activity, attrs, defStyleAttr);

        mHorizontalSlide = horizontalSlide;
        mActivity = activity;
        mScroller = new Scroller(activity);
        mMinX = mMinY = 0;
        mEnable = true;
    }

    //设置不处理滑动事件的x最小值
    public void setMinX(int minX) {
        mMinX = minX;
    }

    //设置不处理滑动事件的y最小值
    public void setMinY(int minY) {
        mMinY = minY;
    }

    //设置是否启用滑动退出activity
    public void setEnable(boolean enable) {
        mEnable = enable;
    }

    //activity与滑动布局绑定
    public void bind() {
        ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
        View child = decorView.getChildAt(0);
        decorView.removeView(child);
        addView(child);
        decorView.addView(this);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //未启用滑动退出功能
        if (!mEnable)
            return false;
        boolean intercept = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                mLastX = x;
                mLastY = y;
                //获取屏幕宽高
                mScreenWidth = getWidth();
                mScreenHeight = getHeight();
                break;
            case MotionEvent.ACTION_MOVE:
                //根据偏移量决定是否捕获滑动事件
                if (mHorizontalSlide)
                    intercept = Math.abs(x - mLastX) > Math.abs(y - mLastY);
                else
                    intercept = Math.abs(x - mLastX) < Math.abs(y - mLastY);
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
        }
        return intercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mEnable)
            return true;
        int currentX;
        int currentY;
        long currentTime;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = (int) event.getX();
                mLastY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                currentTime = System.currentTimeMillis();
                currentX = (int) event.getX();
                currentY = (int) event.getY();
                addSlideData(currentX, currentY, currentTime);
                int dx = mLastX - currentX;
                int dy = mLastY - currentY;
                if (mHorizontalSlide) {
                    if (getScrollX() + dx >= 0) {
                        //滑动到最顶端
                        scrollTo(0, 0);
                    } else if (currentX >= mMinX) {
                        //手指在边缘最小范围内不处理滑动
                        scrollBy(dx, 0);
                    }
                } else {
                    if (getScrollY() + dy >= 0) {
                        //滑动到最左端
                        scrollTo(0, 0);
                    } else if (currentY >= mMinY) {
                        //手指在边缘最小范围内不处理滑动
                        scrollBy(0, dy);
                    }
                }
                mLastX = currentX;
                mLastY = currentY;
                break;
            case MotionEvent.ACTION_UP:
                currentTime = System.currentTimeMillis();
                currentX = (int) event.getX();
                currentY = (int) event.getY();
                addSlideData(currentX, currentY, currentTime);
                if (shouldFinish())
                    slideFinish();
                else
                    slideBack();
                mData.clear();
                break;
            default:
                break;
        }
        return true;
    }

    //添加一组滑动数据
    private void addSlideData(int x, int y, long time) {
        SlideData slideData = new SlideData(time, x, y);
        //数据达到上限，删除第一个数据
        if (mData.size() == DATA_SIZE)
            mData.remove(0);
        mData.add(slideData);
    }

    //根据滑动历史数据判断是否需要finish当前activity
    private boolean shouldFinish() {
        if ((mHorizontalSlide && -getScrollX() >= mScreenWidth / 2) || (!mHorizontalSlide && -getScrollY() >= mScreenHeight / 2))
            return true;
        if (mData.size() < MIN_DATA_SIZE)
            return false;
        int endIndex = mData.size() - 1;
        int startIndex = endIndex;
        float v = 0;
        if (mHorizontalSlide) {
            for (int i = mData.size() - 2; i >= 0; i--) {
                if (mData.get(i).getLocationX() <= mData.get(i + 1).getLocationX())
                    startIndex = i;
                else
                    break;
            }
            if (endIndex == startIndex)
                return false;
            float duration = (float) (mData.get(endIndex).getTime() - mData.get(startIndex).getTime());
            float delta = mData.get(endIndex).getLocationX() - mData.get(startIndex).getLocationX();
            v = delta / duration;
        } else {
            for (int i = mData.size() - 2; i >= 0; i--) {
                if (mData.get(i).getLocationY() <= mData.get(i + 1).getLocationY())
                    startIndex = i;
                else
                    break;
            }
            if (endIndex == startIndex)
                return false;
            float duration = (float) (mData.get(endIndex).getTime() - mData.get(startIndex).getTime());
            float delta = mData.get(endIndex).getLocationY() - mData.get(startIndex).getLocationY();
            v = delta / duration;
        }
        //判断速度是否大于给定的最小值
        return v >= LIMIT;
    }

    //处理自动滑动退出
    private void slideFinish() {
        if (mHorizontalSlide)
            mScroller.startScroll(getScrollX(), 0, -getScrollX() - mScreenWidth, 0
                    , getResources().getInteger(R.integer.activity_auto_slide_finish_or_back));
        else
            mScroller.startScroll(0, getScrollY(), 0, -getScrollY() - mScreenHeight
                    , getResources().getInteger(R.integer.activity_auto_slide_finish_or_back));
        invalidate();
    }

    //处理自动滑动恢复
    private void slideBack() {
        if (mHorizontalSlide)
            mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0
                    , getResources().getInteger(R.integer.activity_auto_slide_finish_or_back));
        else
            mScroller.startScroll(0, getScrollY(), 0, -getScrollY()
                    , getResources().getInteger(R.integer.activity_auto_slide_finish_or_back));
        invalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mHorizontalSlide) {
            if (mScroller.computeScrollOffset()) {
                //未滑动结束，继续
                scrollTo(mScroller.getCurrX(), 0);
                postInvalidate();
            } else if (-getScrollX() == mScreenWidth && mScreenWidth > 0) {
                //结束这个activity
                mActivity.finish();
            }
        } else {
            if (mScroller.computeScrollOffset()) {
                scrollTo(0, mScroller.getCurrY());
                postInvalidate();
            } else if (-getScrollY() == mScreenHeight && mScreenHeight > 0) {
                mActivity.finish();
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    }

    private static class SlideData {
        //记录滑动事件的时间点
        private long mTime;
        //记录事件的x坐标
        private float mLocationX;
        //记录事件的y坐标
        private float mLocationY;

        public SlideData(long time, float x, float y) {
            mTime = time;
            mLocationX = x;
            mLocationY = y;
        }

        public long getTime() {
            return mTime;
        }

        public float getLocationX() {
            return mLocationX;
        }

        public float getLocationY() {
            return mLocationY;
        }
    }
}